# 实现监控中⼼心基础功能
# 在远程主机后台运行，获取主机IP、CPU、内存、硬盘等基本信息，以及主机当前CPU、内存、硬盘等资源占用情况，并存储到MySQL数据库中。
# 第十三周作业一
# 班级：Python五期
# 学员：李子坚
# automonitor.py

import os, sys, time, psutil
import socket
import pymysql

# 从windows下复制文件到Linux
# pscp.exe automonitor.py ubuntu@IP:/home/ubuntu/week13

class Host():
    '''保存主机IP、CPU、内存、硬盘信息及使用情况'''
    def __init__(self):
        '''构造函数，创建数据库连接'''
        self.db = pymysql.connect(host="172.16.0.11",user="tester",password="tester@003244",db="monitordb",charset="utf8")
        self.cursor = self.db.cursor()

    def __del__(self):
        '''析构函数，关闭数据库连接'''
        self.cursor.close()
        self.db.close()

    def host_exists(self, ip):
        '''判断指定IP的主机是否在监控清单里'''
        try:
            #组装查找主机信息sql语句
            sql = "select id from hosts where ip='%s' and state=1"%ip
            #执行查找主机信息的SQL语句
            return self.cursor.execute(sql)
        
        except Exception as error_info:
            # 事务回滚
            self.db.rollback()
            print("SQL执行错误！原因：", error_info)

        return False
        
    def update_hosts(self, ip, cpu, memory, disk):
        '''更新主机信息'''
        try:
            #组装更新主机信息sql语句
            sql = "update hosts set cpu={}, memory={:.2f}, disk={:.1f} where ip='{}'".format(cpu, memory, disk, ip)
            #执行更新主机信息的SQL语句
            self.cursor.execute(sql)
            self.db.commit()
        except Exception as error_info:
            # 事务回滚
            self.db.rollback()
            print("SQL执行错误！原因：", error_info)

    def add_rate(self, table, ip, percent, addtime):
        '''添加cpu/mem/disk使用率'''
        try:
            #组装添加cpu/mem/disk使用率sql语句
            sql = "insert into {}(ip,percent,addtime) values('{}',{:.1f},'{}')".format(table,ip,percent,time.strftime("%Y-%m-%d %H:%M:%S", addtime))
            #指定参数，并执行添加cpu/mem/disk使用率SQL语句
            self.cursor.execute(sql)
            self.db.commit()
        except Exception as error_info:
            # 事务回滚
            self.db.rollback()
            print("SQL执行错误！原因：", error_info)

        
class Monitor():
    '''监控CPU、内存、硬盘使用情况'''
    cpu_data = []

    @classmethod
    def host_ip(cls):
        '''获取主机ip'''
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            s.connect(('8.8.8.8', 80))
            ip = s.getsockname()[0]
        finally:
            s.close()
        return ip

    @classmethod
    def mem_size(cls):
        val = psutil.virtual_memory().total
        #print('内存：{:.2f}G。'.format(val/(1024**3)))
        return val/(1024**3)

    @classmethod
    def mem(cls, max=90):
        val = psutil.virtual_memory().percent
        #print('内存使用率为{:.1f}%。'.format(val))
        return val

    @classmethod
    def cpu_cores(cls, logical=False):
        val = psutil.cpu_count(logical=False)
        #print('CPU：%d核。'%val)
        return val
        
    @classmethod
    def cpu(cls, max=90):
        val = psutil.cpu_percent(1)
        #print('CPU使用率为{:.1f}%。'.format(val))
        return val

    @classmethod
    def disk_size(cls):
        val = psutil.disk_usage('/').total
        #print('硬盘：{:.1f}G。'.format(val/(1024**3)))
        return val/(1024**3)

    @classmethod
    def disk(cls, max=90):
        val = psutil.disk_usage('/').percent
        #print('硬盘使用率为{:.1f}%。'.format(val))
        return val

def main():
    host = Host()
    host_ip = Monitor.host_ip()
    host.update_hosts(host_ip, Monitor.cpu_cores(), Monitor.mem_size(), Monitor.disk_size())
    
    while True:
        #如果主机还在监控清单里
        if host.host_exists(host_ip):
            monitor_time = time.gmtime()
            host.add_rate('cpu_rate', host_ip, Monitor.cpu(), monitor_time)
            host.add_rate('mem_rate', host_ip, Monitor.mem(), monitor_time)
            host.add_rate('disk_rate', host_ip, Monitor.disk(), monitor_time)
        else:   #不在监控清单里
            break
        time.sleep(9)


# 判断当前执行是否为主程序，并调度主函数获取主机CPU、内存、硬盘等信息 
if __name__ == '__main__':
    main()
